package com.item.mobile;

import static org.apache.commons.lang.StringUtils.isBlank;

import java.util.Date;
import java.util.List;
import java.util.UUID;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.base.mobile.MobException;
import com.base.mobile.MobileInfo;
import com.base.mobile.server.annotation.Mobile;
import com.base.mobile.server.annotation.MobileMethod;
import com.base.util.DateUtil;
import com.base.util.StringUtil;
import com.item.dao.model.MobileVerify;
import com.item.dao.model.MobileVerifyExample;
import com.item.dao.model.RegisterVerify;
import com.item.dao.model.RegisterVerifyExample;
import com.item.dao.model.User;
import com.item.dao.model.UserExample;
import com.item.dao.model.WelcomePage;
import com.item.dao.model.WelcomePageExample;
import com.item.exception.JSONRepUtils;
import com.item.service.MobileVerifyService;
import com.item.service.RegisterVerifyService;
import com.item.service.UserService;
import com.item.util.ConstantResources;
import com.item.util.EmojiFilter;
import com.item.util.MD5C;
import com.item.util.MyDateUtils;
import com.item.util.ShortMessageSender;
import com.mobile.api.proto.MAppUser.MUser;
import com.mobile.api.proto.MAppUser.MUserList;
import com.mobile.api.proto.MSystem.MRet;

import static com.item.mobile.MobileUtil.checkParam;

@Component
@Mobile
public class MAppUser {
	@Autowired 
	private UserService userService;
	@Autowired
	private MobileVerifyService verifyService;
	@Autowired
	private RegisterVerifyService registerVerifyService;
	
	
	@MobileMethod(methodno = "MLogin",isLogin=false)
	public MUser.Builder login(MobileInfo mobileInfo, String device, 
			String account,
			String password, String qqAccount,
			String wxAccount, String wbAccount,
			String phone) throws Exception {
		checkParam(device, "device");
		
		MUser.Builder ret = MUser.newBuilder();
		User user = assembleUser( account,
				 password,  qqAccount,
				 wxAccount,  wbAccount,
				 phone,  device,  mobileInfo.getDeviceid());

		UserExample example = new UserExample();
		
		boolean isregistered = false;
		if(!isBlank(qqAccount)) { //qq account login
			example.createCriteria().andQqAccountEqualTo(qqAccount);
		} else if(!isBlank(wxAccount)) {
			example.createCriteria().andWxAccountEqualTo(wxAccount);
		} else if(!isBlank(wbAccount)) {
			example.createCriteria().andWbAccountEqualTo(wbAccount);
		} else if(!isBlank(password) && !isBlank(phone)) {
			isregistered = true;
			example.createCriteria().andPasswordEqualTo(password)
			.andPhoneEqualTo(phone);
		} else if(!isBlank(password) && !isBlank(account)) {
			isregistered = true;
			example.createCriteria().andAccountEqualTo(account.toUpperCase())
			.andPasswordEqualTo(password);
		} else { //there is no parameter could be used in login, error
			throw new MobException(MEnumError.LOST_PARAM_ERROR);
		}
		
		List<User> list = userService.selectByExample(example);
		if(list.size() > 0) { //old user, login success
			user = list.get(0);
			user.setDevice(device);
			user.setDeviceid(mobileInfo.getDeviceid());
		} else {
			if(isregistered) { //old user, login failure
				throw new MobException(MEnumError.LOGIN_FAILURE_ERROR);
			} else {
				user = userService.getNextAccount(user);
			}
		}
		
		//execute here, login/register success
		assembleData(ret, user, updateMobileVerify(mobileInfo, user));	
		ret.setPasswordEncrypt(StringUtil.emptyIfBlank(user.getPassword()));
		return ret;
	}
	
	@MobileMethod(methodno = "MRegister",isLogin=false)
	public MUser.Builder register(MobileInfo mobileInfo, String device,
			String phone, String code) throws Exception {
		checkParam(code, "code");
		checkParam(phone, "phone");
		checkParam(device, "device");
		
		MUser.Builder ret = MUser.newBuilder();
		
		Date reSendDeadLine = new Date(System.currentTimeMillis() - 
				ConstantResources.VERIFY_INTEVAL );
		RegisterVerifyExample exampleR = new RegisterVerifyExample();
		exampleR.createCriteria().andPhoneEqualTo(phone)
		.andIsVEqualTo(0)
		.andSendTimeGreaterThanOrEqualTo(reSendDeadLine);
		
		List<RegisterVerify> listR = registerVerifyService.selectByExample(exampleR);
		
		if(listR.size() > 0) {
			RegisterVerify first = listR.get(0);
			if(code.equals(first.getVerify())) {
				first.setIsV(1); //
				registerVerifyService.updateByPrimaryKeySelective(first);
				
				UserExample example = new UserExample();
				example.createCriteria().andPhoneEqualTo(phone);
				List<User> list = userService.selectByExample(example);
				User user = null;
				if(list.size() > 0) {
					user = list.get(0);
					user.setDevice(device);
					user.setDeviceid(mobileInfo.getDeviceid());
				} else {
					user = new User();
					user.setPhone(phone);
					user.setDevice(device);
					user.setDeviceid(mobileInfo.getDeviceid());
					user = userService.getNextAccount(user);
				}
				if(ConstantResources.ISDEBUG)
					//System.out.println("here");
				assembleData(ret, user, updateMobileVerify(mobileInfo, user));
			} else {
				throw new MobException(MEnumError.MOBILE_VERIFY_CODE_ERROR);
			}
		} else { //need send again
			throw new MobException(MEnumError.MOBILE_NOTINTABLE_ERROR);
		}
		
		return ret;
	}
	
	@MobileMethod(methodno = "MPasswdChange",isLogin=true)
	public MRet.Builder password(MobileInfo mobileInfo, String passwordOld, String password,
			String nickname, Integer sex)
			throws Exception {
		checkParam(password, "password");
		
		if(password.equals(MD5C.calcMD5("", false))){
			throw new MobException(MEnumError.PASSWORD_EMPTY_ERROR);
		}
		
		MRet.Builder ret = MRet.newBuilder();
		
		modifyInfo(ret, mobileInfo, passwordOld, password, nickname,
				 sex, null, null);
		
		return ret;
	}
	
	private void modifyInfo(MRet.Builder ret, MobileInfo mobileInfo, String passwordOld, String password,
			String nickname, Integer sex, String headimg, String email)throws Exception{
		
		//说明是修改密码，需要先验证旧的密码
		if(StringUtils.isNotBlank(passwordOld)){
			UserExample uex = new UserExample();
			uex.createCriteria().andIdEqualTo(mobileInfo.getUserid()).andPasswordEqualTo(passwordOld);
			List<User> lists = userService.selectByExample(uex);
			if(lists == null || lists.size() < 1)
				throw new MobException(MEnumError.OLD_PASSWORD_ERROR);
		}
		User user = new User();
		user.setId(mobileInfo.getUserid());
		user.setPassword(password);
		user.setNickname(nickname);
		user.setHeadimg(headimg);
		user.setEmail(email);
		user.setSex(sex);
		user.setModifyTime(new Date());
		int rows = userService.updateByPrimaryKeySelective(user);
		if(rows > 0) {
			ret.setCode(1);
			ret.setMsg("修改成功");
			//synchronize user info in other tables
			if(StringUtils.isNotBlank(nickname) || StringUtils.isNotBlank(headimg)){
				userService.synchronizeInfo(mobileInfo.getUserid(), nickname, headimg);
			}
		} else {
			ret.setCode(0);
			ret.setMsg("修改失败");
		}
	}
	
	@MobileMethod(methodno = "MUpdateUserInfo",isLogin=true)
	public MRet.Builder info(MobileInfo mobileInfo, String nickname,
			Integer sex, String headimg, String email) throws Exception {
//		checkParam(nickname, "nickname");
//		checkParam(sex, "sex");
//		checkParam(headimg, "headImg");
		if(StringUtils.isNotBlank(nickname)){
			nickname = EmojiFilter.filterEmoji(nickname);
		}
		MRet.Builder ret = MRet.newBuilder();
		
		modifyInfo(ret, mobileInfo, null, null, nickname, 
			 sex, headimg, email);
		
		return ret;
	}
	
	/**
	 * 退出登录
	 */
	@MobileMethod(methodno = "MLogout",isLogin=true)
	public MRet.Builder logout(MobileInfo mobileInfo)throws Exception{
		User user = userService.selectByPrimaryKey(mobileInfo.getUserid());
		if(user!=null){
			user.setPushid(null);
			user.setDevice(null);
			user.setBadge(0);
			userService.updateByPrimaryKey(user);
		}
		
		MRet.Builder ret = MRet.newBuilder();
		ret.setCode(1);
		return ret;
	}
	
	/**
	 * 根据deviceid给用户分配账号
	 * @url /mobile?methodno=MGetWelcomePage&debug=&deviceid=&appid=
	 * @return
	 */
	@MobileMethod(methodno = "MGetWelcomePage",isLogin=false,isPage=false)
	public MUser.Builder getWelcomePage(MobileInfo mobileInfo, String device)throws Exception{
//		
		MUser.Builder ret = MUser.newBuilder();
//		System.out.println("dd" + mobileInfo.getDeviceid());
		UserExample uex = new UserExample();
		uex.createCriteria().andDeviceidEqualTo(mobileInfo.getDeviceid());
		List<User> users = userService.selectByExample(uex);
		//说明该设备还没用被用过，此时需要分配信息给它
		if(users == null || users.size() < 1){
			User user = assembleUser("", "", "", "", "", "", device, mobileInfo.getDeviceid());
			user = userService.getNextAccount(user);
			assembleData(ret, user, updateMobileVerify(mobileInfo, user));
//			System.out.println(ret.getHasPassword());
		}else if(users.size() == 1){
			//这时说明该设备只被一个账号登录过
			User user = users.get(0);
			assembleData(ret, user, updateMobileVerify(mobileInfo, user));
		}else{
			//IOS:默认选择非第三方登录的那个号返回
			for(User u : users){
				if(StringUtils.isBlank(u.getPhone()) && StringUtils.isBlank(u.getQqAccount()) &&StringUtils.isBlank(u.getWbAccount())&&StringUtils.isBlank(u.getWxAccount())){
					assembleData(ret, u, updateMobileVerify(mobileInfo, u));
					break;
    			}
			}
			//ret.setVerify("");
		}
//		System.out.println(ret.toString());
		return ret;
	}
	
	@MobileMethod(methodno = "MGetWelcomePageAndroid",isLogin=false,isPage=false)
	public MUserList.Builder getWelcomePageAndroid(MobileInfo mobileInfo, String device)throws Exception{		
		MUserList.Builder rets = MUserList.newBuilder();
		MUser.Builder ret = MUser.newBuilder();
//		System.out.println("dd" + mobileInfo.getDeviceid());
		UserExample uex = new UserExample();
		uex.createCriteria().andDeviceidEqualTo(mobileInfo.getDeviceid());
		List<User> users = userService.selectByExample(uex);
		//说明该设备还没用被用过，此时需要分配信息给它
		if(users == null || users.size() < 1){
			User user = assembleUser("", "", "", "", "", "", device, mobileInfo.getDeviceid());
			String passUnencrpyt = ShortMessageSender.verifyGenerator();
			user.setPassword(MD5C.calcMD5(passUnencrpyt, false));
			user = userService.getNextAccount(user);
			assembleData(ret, user, updateMobileVerify(mobileInfo, user));
			ret.setPassword(passUnencrpyt);
			ret.setPasswordEncrypt(user.getPassword());
			rets.addUser(ret);
		}else if(users.size() == 1){
			//这时说明该设备只被一个账号登录过
			User user = users.get(0);
			assembleData(ret, user, updateMobileVerify(mobileInfo, user));
			ret.setPasswordEncrypt(user.getPassword());
			rets.addUser(ret);
		}else{
			//IOS:如果有两个以上的账号在这台设备上登录过，那么就只能让用户选择登录了  安卓：返回登录过的用户列表，包括相应用户的密码
			int j = 0;
			for(User u : users){
				ret = MUser.newBuilder();
				ret.setAccount(u.getAccount());
				ret.setPasswordEncrypt(u.getPassword());
				assembleData(ret, u, "");
				rets.addUser(ret);
				j ++;
				if(j >= 5){
					break;
				}
			}
		}
//		System.out.println(ret.toString());
		return rets;
	}
	
	/**
	 * 更新登录验证
	 */
	private String updateMobileVerify(MobileInfo mobileInfo, User user){
		MobileVerifyExample mv = new MobileVerifyExample();
		MobileVerify mobileVerify = new MobileVerify();
		mobileVerify.setModifyTime(new Date());
		mobileVerify.setVerify(UUID.randomUUID().toString());
		mobileVerify.setDeviceId(mobileInfo.getDeviceid());
		mobileInfo.setUserid(StringUtil.emptyIfBlank(user.getId()));
		
		mv.createCriteria().andUserIdEqualTo(mobileInfo.getUserid());
		int count = verifyService.updateByExampleSelective(mobileVerify, mv);
		if(count==0){
			mobileVerify.setCreateTime(new Date());
			mobileVerify.setDeviceId(mobileInfo.getDeviceid());
			mobileVerify.setUserId(mobileInfo.getUserid());
			mobileVerify.setModifyTime(null);
			verifyService.insert(mobileVerify);
		}
		user.setPushid(mobileVerify.getVerify());
		//update device, deviceid, verify, pushid
		userService.updateByPrimaryKeySelective(user); 
		user.setBadge(0);
		
		return mobileVerify.getVerify();
	}
	
	public static void assemblePasswordData(MUser.Builder ret, String pass){
		ret.setPassword(pass);
	}
	
	/**
	 * assemble user's data for response
	 * @param ret
	 * @param user
	 * @param verify
	 */
	public static void assembleData(MUser.Builder ret, User user, String verify) {
		if(user != null) {
			ret.setAccount(StringUtil.emptyIfBlank(user.getAccount()));
			ret.setEmail(StringUtil.emptyIfBlank(user.getEmail()));
			ret.setHeadImg(StringUtil.emptyIfBlank(user.getHeadimg()));
			ret.setId(StringUtil.emptyIfBlank(user.getId()));
			ret.setNickname(StringUtil.emptyIfBlank(user.getNickname()));
			ret.setPhone(StringUtil.emptyIfBlank(user.getPhone()));
			ret.setSex(user.getSex() == null ? 0 : user.getSex());
			ret.setVerify(StringUtil.emptyIfBlank(verify)); 
			ret.setSubjectEng(StringUtil.emptyIfBlank(user.getSubjectEng()));
			ret.setSubjectMajor1(StringUtil.emptyIfBlank(user.getSubjectMajor1()));
			ret.setSubjectMajor2(StringUtil.emptyIfBlank(user.getSubjectMajor2()));
			ret.setSubjectMath(StringUtil.emptyIfBlank(user.getSubjectMath()));
			ret.setSubjectPolity(StringUtil.emptyIfBlank(user.getSubjectPolity()));
			ret.setStartDay(MyDateUtils.dayDiff(user.getCreateTime(), new Date()) + 1);
			ret.setRestDay(MyDateUtils.dayDiff(new Date(), DateUtil.strToDate(ConstantResources.OVERDATE, "yyyy-MM-dd")) + 1);
			//
			if(StringUtils.isBlank(user.getPassword())){
				if(StringUtils.isBlank(user.getPhone()) && StringUtils.isBlank(user.getQqAccount()) && StringUtils.isBlank(user.getWbAccount()) && StringUtils.isBlank(user.getWxAccount())){
    				ret.setHasPassword(-1);
    			}else{
    				ret.setHasPassword(0);
    			}
			}else{
				ret.setHasPassword(1);
			}
			ret.setDiaryDefault(ConstantResources.DIARYDEFAULT);
			ret.setAboutusUrl(ConstantResources.ABOUTURL+"?t="+System.currentTimeMillis());
			ret.setContactUrl(ConstantResources.CONTACTURL+"?t="+System.currentTimeMillis());
			ret.setCreateTime(MyDateUtils.parseDateWithDay(user.getCreateTime()));
		}
	}
	
	/**
	 * assemble entity user for login/register
	 * @param account
	 * @param password
	 * @param qqAccount
	 * @param wxAccount
	 * @param wbAccount
	 * @param phone
	 * @param device
	 * @param deviceid
	 * @return
	 */
	public static User assembleUser(String account,
			String password, String qqAccount,
			String wxAccount, String wbAccount,
			String phone, String device, String deviceid) {
		User user = new User();
		
		user.setAccount(account);
		user.setDevice(device);
		user.setDeviceid(deviceid);
		user.setPassword(password);
		user.setPhone(phone);
		user.setQqAccount(qqAccount);
		user.setWxAccount(wxAccount);
		user.setWbAccount(wbAccount);
		
		return user;
		
	}
}
